﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Reflection;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BrainTechLLC.ThreadSafeObjects;
using System.Runtime.Serialization;

namespace BrainTechLLC
{
    [Serializable]
    [DataContract]
    public class Template : GameThingBaseClass, IGameThing, IHasPropertyData, ISpecifiesTypeName, ITemplate
    {
        [NonSerialized, XmlIgnore]
        public static readonly ThreadSafeLookup<string, Template> AllTemplates = new ThreadSafeLookup<string, Template>();

        [DataMember]
        public string _typeName;

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public new string TypeName
        {
            get { return _typeName; }
            set
            {
                if (!_typeName.AreEqual(value))
                {
                    OnPropertyChanging("TypeName", _typeName, value);
                    _typeName = value;
                    OnPropertyChanged("TypeName", _typeName, value);
                }
            }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public string FriendlyName
        {
            get { return _name == null ? string.Empty : _name._name; }
            set
            {
                if (!Name.Name.AreEqual(value))
                {
                    OnPropertyChanging("FriendlyName", Name.Name, value);
                    Name.Name = value;
                    OnPropertyChanged("FriendlyName", Name.Name, value);
                }
            }
        }

        [DataMember]
        public PropertyData _propsToSet;

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public PropertyData PropertiesToSet
        {
            get
            {
                return _propsToSet;
            }
            set
            {
                if (!_propsToSet.AreEqual(value))
                {
                    OnPropertyChanging("PropertiesToSet", _propsToSet, value);
                    _propsToSet = value;
                    OnPropertyChanged("PropertiesToSet", _propsToSet, value);
                }
            }
        }

        public Template()
        {
        }

        public override void Register()
        {
            base.Register();
            RegisterTemplate();
        }

        public virtual void RegisterTemplate()
        {
            AllTemplates.AddOrSet(FriendlyName, this);
        }

        public virtual IFromTemplate CreateInstance(List<object> arguments)
        {
            Type t = TypeProvider.GetInstance().GetType(TypeName, false);

            if (t == null)
                return null;

            ConstructorInfo ci = TypeProvider.GetInstance().GetConstructorInfo(t);
            object o = ci.Invoke(null);
            IFromTemplate newObject = o as IFromTemplate;
            newObject.TemplateID = AssociatedID;
            newObject.TemplateObject = this;
            newObject.Register();
            // newObject.States = TODO
            AddDefaults(newObject);
            if (PropertiesToSet != null && PropertiesToSet._props != null)
            {
                foreach (IdentifierAndValue kvp in PropertiesToSet._props.AllItems)
                {
                    PropertyInfo prop = t.GetProperty(kvp.Identifier);
                    if (prop != null)
                    {
                        prop.SetValue(o, Convert.ChangeType(kvp.Value, prop.PropertyType, null), null);
                    }
                }
            }

            GameThingBaseClass baseClass = newObject as GameThingBaseClass;
            if (baseClass != null)
            {
                baseClass._name = Name.CreateCopy();                
            }

            return newObject;
        }

        public virtual void AddDefaults(IFromTemplate item)
        {
            item.ThingProperties = this.ThingProperties.MakeCopy();
        }

        public virtual T CreateInstance<T>(List<object> arguments) where T : class, IFromTemplate
        {
            return CreateInstance(arguments) as T;
        }
    }
}
